Wraz z wydaniem ABAP 7.40 język ABAP przeszedł największą ewolucję od lat. Kolejne wersje z linii 7.4x i 7.5x wprowadziły nowoczesny, bardziej deklaratywny styl programowania, zbliżony do współczesnych języków wysokiego poziomu.
Pojawiły się m.in. deklaracje inline, wyrażenia funkcyjne (VALUE, FOR, COND), nowy styl Open SQL oraz liczne usprawnienia poprawiające czytelność, bezpieczeństwo typów i produktywność programisty - przy jednoczesnym zachowaniu pełnej kompatybilności wstecznej.
Celem tego artykułu jest syntetyczne podsumowanie najważniejszych zmian wprowadzonych w wersjach ABAP 7.40-7.5x, ze szczególnym naciskiem na praktyczne różnice w składni, typowe pułapki oraz elementy, które warto znać zarówno w codziennej pracy, jak i podczas rozmów technicznych.
Złota zasada mówi: nowa składnia = czytelność , stara składnia =
kontrola. Nowa składnia nie zastępuje starej - obydwa style mogą
współistnieć w jednym programie (backward compatibility). Niektóre
wyrażenia mogą mieć inne zachowanie (np. jak obsługa błędów, wartości
domyślne) niż stara składnia - warto testować przy konwersji starego
kodu.
Inline DATA
VALUE / FOR / FILTER / REDUCE
COND / SWITCH
String templates | |
Table expressions
Enums
INT8, DECFLOAT, UTCLONG
Virtual Sort
+=, &&=
Lepsze Open SQL (@DATA, expressions)
LOOP … STEP
ASSIGN ELSE UNASSIGN
RETURN expr
CORRESPONDING MAPPING / DEFAULT
DATA: lv_sum TYPE i. lv_sum = 5 + 10.
Możesz deklarować zmienne bez wcześniejszego DATA: na górze programu - w samym miejscu użycia - jest krócej:
DATA(result) = 5 + 10.
`DATA: wa TYPE scarr.
LOOP AT it_scarr INTO wa.
WRITE: wa-carrid.
ENDLOOP.`
LOOP AT it_scarr INTO DATA(wa). WRITE wa-carrid. ENDLOOP.
Albo jeszcze lepiej (field-symbol):
LOOP AT it_scarr ASSIGNING FIELD-SYMBOL(<wa>). WRITE <wa>-carrid. ENDLOOP.
READ TABLE itab INTO wa WITH KEY id = lv_id. IF sy-subrc = 0. lv_name = wa-name. ENDIF.
DATA(lv_name) = itab[ id = lv_id ]-name.
Z kontrolą istnienia:
IF line_exists( itab[ id = lv_id ] ). DATA(lv_name) = itab[ id = lv_id ]-name. ENDIF.
IF lv_score > 50. lv_result = 'PASS'. ELSE. lv_result = 'FAIL'. ENDIF.
DATA(lv_result) = COND string( WHEN lv_score > 50 THEN 'PASS' ELSE 'FAIL' ).
CASE lv_status. WHEN 'A'. lv_text = 'Active'. WHEN 'I'. lv_text = 'Inactive'. ENDCASE.
DATA(lv_text) = SWITCH string( lv_status WHEN 'A' THEN 'Active' WHEN 'I' THEN 'Inactive' ELSE 'Unknown' ).
CONCATENATE 'User:' lv_user 'Age:' lv_age INTO lv_text SEPARATED BY space.
DATA(lv_text) = |User: { lv_user } Age: { lv_age }|.
`DATA: it_scarr TYPE TABLE OF scarr.
SELECT * FROM scarr INTO TABLE it_scarr.`
SELECT * FROM scarr INTO TABLE @DATA(it_scarr).
SELECT SINGLE carrname INTO lv_name FROM scarr WHERE carrid = lv_id.
SELECT SINGLE carrname FROM scarr INTO @DATA(lv_name) WHERE carrid = @lv_id.
`DATA: itab TYPE TABLE OF i,
lv_i TYPE i.
DO 5 TIMES.
lv_i = sy-index.
APPEND lv_i TO itab.
ENDDO.`
DATA(itab) = VALUE #( FOR i = 1 UNTIL i > 5 ( i ) ).
LOOP AT it_employees INTO wa. IF wa-age > 30. APPEND wa TO it_filtered. ENDIF. ENDLOOP.
DATA(it_filtered) = FILTER #( it_employees WHERE age > 30 ).
lv_sum = 0. LOOP AT it_numbers INTO lv_num. lv_sum = lv_sum + lv_num. ENDLOOP.
DATA(lv_sum) = REDUCE i( INIT x = 0 FOR lv_num IN it_numbers NEXT x = x + lv_num ).
Artykuł „ABAP 7.5x Quick Reference” na SAP Community to praktyczne krótkie podsumowanie najważniejszych nowości i rozszerzeń składni ABAP w wersjach 7.50-7.58 (tzw. 7.5x releases)*. Poniżej przedstawiam krótkie podsumowanie artykułu:
Od ABAP 7.54 wprowadzono krótsze operatory przypisania:
+=, -=, *=, /= (np. num += 1).&&= do konkatenacji stringów (np. text &&= | more |).num = num + … czy CONCATENATE.`lv_counter = lv_counter + 1.
CONCATENATE lv_text ' more' INTO lv_text.`
lv_counter += 1. lv_text &&= ' more'.
ASSIGN … ELSE UNASSIGN — jeśli nie ma pola, to od razu odassignuj.ASSIGN struct-(comp) – dynamiczne przypisanie komponentów struktury wg ich nazw lub indeksów.ASSIGN COMPONENT lv_comp OF STRUCTURE ls_struc TO <fs>. IF sy-subrc <> 0. UNASSIGN <fs>. ENDIF.
ASSIGN COMPONENT lv_comp OF STRUCTURE ls_struc TO <fs> ELSE UNASSIGN.
RETURN expr (7.58)Zamiast deklarować zmienną pośrednią w metodzie, możesz bezpośrednio zwrócić wynik w jednym wyrażeniu:
RETURN ipow( base = root exp = 2 ).
To ułatwia pisanie metod z krótszym kodem.
METHOD get_sum. DATA lv_sum TYPE i. lv_sum = iv_a + iv_b. rv_sum = lv_sum. ENDMETHOD.
METHOD get_sum. RETURN iv_a + iv_b. ENDMETHOD.
W nowszych wersjach pojawiły się m.in.:
INT8 - 8-bajtowa liczba całkowita (7.50)
UTCLONG - dokładny znacznik czasu (7.54)
DECFLOAT16, DECFLOAT34 - liczby zmiennoprzecinkowe w formacie dziesiętnym (7.54)
Typy DDIC jak DATN, TIMN, GEOM_EWKB
Możesz definiować typy wyliczeniowe, co pozwala na ograniczenie wartości zmiennej do przyjętej listy:
`CONSTANTS:
c_open TYPE i VALUE 1,
c_closed TYPE i VALUE 2.
DATA lv_status TYPE i.
lv_status = c_open.`
`TYPES BEGIN OF ENUM status.
open,
closed
END OF ENUM status.
DATA(lv_status) = status-open.`
Wskazana nowość zapewnia:
Mechanizm sortowania bez fizycznego sortowania tabeli - otrzymujesz indeks sortujący, który możesz potem wykorzystać do odczytu danych w żądanej kolejności. Przydatne przy wielokrotnych sortowaniach.
SORT itab BY name age. LOOP AT itab INTO wa. ENDLOOP.
`DATA(sort_tab) = cl_abap_itab_utilities=>virtual_sort(
im_table = itab
im_sort = VALUE #( ( name = 'NAME' ascending = abap_true )
( name = 'AGE' ascending = abap_true ) )
).
LOOP AT sort_tab INTO DATA(idx).
DATA(wa) = itab[ idx ].
ENDLOOP.`
Nowy sposób oznaczania, które pola struktury mają zostać uaktualnione w update’ach baz danych.
Możesz określić, które komponenty tabeli bazowej mają zostać zmienione przy operacji UPDATE.
`ls_db-field1 = lv_val.
ls_db-field2 = lv_val2.
UPDATE ztable FROM ls_db.`
`DATA(ind) = VALUE ztable_ind(
field1 = abap_true
).
ls_db-field1 = lv_val.
UPDATE ztable FROM ls_db INDICATORS ind.`
Mind-blowing opcje:
EXPANDING NESTED TABLES - automatyczne rozwijanie zagnieżdżonych tabelKEEPING TARGET LINES - zachowanie linii w tabeli docelowej podczas kopiowaniaMOVE-CORRESPONDING ls_src TO ls_tgt.
MOVE-CORRESPONDING ls_src TO ls_tgt EXPANDING NESTED TABLES KEEPING TARGET LINES.
Możesz teraz iterować po tabeli z krokiem n zamiast domyślnego 1:
LOOP AT itab ASSIGNING <fs> STEP 2.
Działa też dla pętli FOR, APPEND, DELETE, INSERT, VALUE.
`DATA lv_idx TYPE i VALUE 1.
WHILE lv_idx <= lines( itab ).
READ TABLE itab INDEX lv_idx INTO wa.
lv_idx = lv_idx + 2.
ENDWHILE.`
LOOP AT itab INTO DATA(wa) STEP 2. ENDLOOP.
Rozszerzone mapowanie struktur z użyciem:
MAPPING - dopasowanie konkretnych komponentówDEFAULT - wartość domyślna, gdy brak danychls_tgt-field1 = ls_src-fieldA. ls_tgt-field2 = 'X'.
DATA(ls_tgt) = CORRESPONDING ty_target( ls_src MAPPING field1 = fieldA DEFAULT field2 = 'X' ).
Artykuł skrótowo wspomina też (w kontekście 7.5x) rozwój CDS Views, które są kluczowe przy nowoczesnym modelowaniu danych w S/4HANA i RAP - z dodatkowymi funkcjami CDS w kolejnych wersjach ABAP.
Inline DATA
VALUE / FOR / FILTER / REDUCE
COND / SWITCH
String templates | |
Table expressions
Enums
INT8, DECFLOAT, UTCLONG
Virtual Sort
+=, &&=
Lepsze Open SQL (@DATA, expressions)
LOOP … STEP
ASSIGN ELSE UNASSIGN
RETURN expr
CORRESPONDING MAPPING / DEFAULT